import Taro from '@tarojs/taro';
import { from } from "rxjs";
import { mergeMap, retryWhen, map, catchError } from "rxjs/operators";
import { ButtonProps } from '@tarojs/components';
import { PaginationResponse } from '@datorama/akita';

import { TokenInfo, TokenCheckInfo, LoginResult, JsCode, OrgTokenInfo } from "@/models/Auth";
import CONFIG from "@/config";
import { genericRetryStrategy, rxRequest } from "@/utils/rxHelpers";
import { ApprovalStatus, OrgApproveParams, PersonApproveParams, UserUpdateParams, AnchorsItem, OrgsItem, FansItem } from '@/models/request/userReq';
import { AnchorlatestRsp, GetAnchorDetailsRsp, GetMeRsp, GetOrgDetailsRsp, Plans, SubscriptionRsp, } from '@/models/response/userRsp';

export default {
  //**service层只有异步的网络请求，没有直接访问store的逻辑，facade层融合service和store的相关逻辑
  // 检测登录状态，返回 Observable
  checkLoginSvc(token: string) {
    return rxRequest<TokenCheckInfo>({
      url: CONFIG.BASE_URL + "/v1/user/checkToken",
      data: { token },
      method: "POST"
    })
  },

  // 微信低级登录绑定(只绑定openid)
  wxBindLiteSvc() {
    return from(Taro.login())
      .pipe(
        retryWhen(genericRetryStrategy()),
        mergeMap(loginRes => {
          return rxRequest<LoginResult>({
            url: CONFIG.BASE_URL + "/v1/user/wxBindLite",
            data: { js_code: loginRes.code, appId: CONFIG.APPID },
            method: "POST"
          })
        })
      )
  },

  wxBindProSvc() {
    return from(Taro.login())
      .pipe(
        retryWhen(genericRetryStrategy()),
        mergeMap(loginRes => {
          return from(Taro.getUserInfo({ withCredentials: true, lang: "zh_CN" }))
            .pipe(
              retryWhen(genericRetryStrategy()),
              mergeMap(userRes => {
                return rxRequest<LoginResult>({
                  url: CONFIG.BASE_URL + "/v1/user/wxBindPro",
                  data: {
                    js_code: loginRes.code,
                    appId: CONFIG.APPID,
                    iv: userRes.iv,
                    encryptData: userRes.encryptedData
                  },
                  method: "POST"
                })
              })
            )
        })
      )
  },

  wxBindPhoneSvc(js_code: string, detail: ButtonProps.onGetPhoneNumberEventDetail) {
    return rxRequest<LoginResult>({
      url: CONFIG.BASE_URL + "/v1/user/wxBindPhone",
      data: {
        js_code,
        appId: CONFIG.APPID,
        iv: detail.iv,
        encryptedData: detail.encryptedData
      },
      method: "POST"
    })
  },

  // todo 需要判断refresh_token过期的情形
  refreshTokenSvc(refresh_token: string) {
    return rxRequest<TokenInfo>({
      url: CONFIG.BASE_URL + "/v1/user/refreshJwt",
      data: { grant_type: "refresh_token", refresh_token }, // 请求的参数",
      method: "POST",
    })
  },

  /**
     * 小程序冷启动调用一次，然后需要登录的逻辑再调用一次
     * @returns js_code
     */
  wxLoginSvc(codeObj: JsCode) {
    const wxLogin$ = from(Taro.login())
      .pipe(
        retryWhen(genericRetryStrategy()),
        map(res => {
          const codeObj1: JsCode = {
            code: res.code,
            //js_code五分钟过期
            expires: new Date().getTime() + 5 * 60 * 1000
          }
          return codeObj1;
        })
      )

    //不管code是否为空都要wx.checkSession
    return from(Taro.checkSession())
      .pipe(
        retryWhen(genericRetryStrategy()),
        //js_code未过期则直接返回
        map(() => {
          const timeGap = codeObj.expires - new Date().getTime();
          // 如果有缓存并且jscode不为空并且未超过5分钟
          if (codeObj.code && 0 <= timeGap && timeGap <= 5 * 60 * 1000) {
            return codeObj;
          } else {
            throw new Error("js_code需要重新刷新");
          }
        }),
        //js_code已过期重新wx.login
        catchError(() => {
          return wxLogin$;
        })
      )
  },

  getMeSvc() {
    return rxRequest<GetMeRsp>({
      url: CONFIG.BASE_URL + "/v1/user/me",
      // 需要授权访问
      withJwt: true
    })
  },

  //个人认证
  personApproveSvc(data: PersonApproveParams) {
    return rxRequest({
      url: CONFIG.BASE_URL + "/v1/user/approve/person",
      // 需要授权访问
      withJwt: true,
      data,
      method: "POST"
    })
  },

  //机构认证
  orgApproveSvc(data: OrgApproveParams) {
    return rxRequest({
      url: CONFIG.BASE_URL + "/v1/user/approve/organization",
      // 需要授权访问
      withJwt: true,
      data,
      method: "POST"
    })
  },

  //切换机构
  changeOrgSvc(orgId: string) {
    return rxRequest<OrgTokenInfo>({
      url: CONFIG.BASE_URL + `/v1/user/changeOrg/${orgId}`,
      withJwt: true,
      method: "POST"
    })
  },

  //编辑个人信息
  userUpdateSvc(data: UserUpdateParams) {
    return rxRequest({
      url: CONFIG.BASE_URL + "/v1/user/profile",
      // 需要授权访问
      withJwt: true,
      data,
      method: "PUT"
    })
  },

  // 认证状态
  approveStatusSvc() {
    return rxRequest<ApprovalStatus>({
      url: CONFIG.BASE_URL + "/v1/user/approve/status",
      // 需要授权访问
      withJwt: true,
    })
  },

  //提交激活码
  activateCodeSvc(code: string) {
    return rxRequest({
      url: CONFIG.BASE_URL + '/v1/user/subs/activate/plan',
      withJwt: true,
      data: { code },
      method: 'POST'
    })
  },

  //关注用户、机构
  addFollowSvc(toUser: string, toOrg: string, ops: boolean) {
    return rxRequest({
      url: CONFIG.BASE_URL + '/v1/user/follow/addFollow',
      withJwt: true,
      data: { toUser, toOrg, ops },
      method: 'POST'
    })
  },


  //查询关注状态
  isFollowSvc(anchorId: string, orgId: string) {
    return rxRequest({
      url: CONFIG.BASE_URL + '/v1/user/follow/isFollowed',
      withJwt: true,
      data: { anchorId, orgId },
      method: 'POST'
    })
  },

  //获取关注的主播列表数据
  getAnchorsSvc(pageNum: number, pageSize: number) {
    return rxRequest<PaginationResponse<AnchorsItem>>({
      url: CONFIG.BASE_URL + "/v1/user/follow/getAnchors",
      withJwt: true,
      data: { pageNum, pageSize },
      method: "POST"
    })
  },

  //获取关注的机构列表数据
  getOrgsSvc(pageNum: number, pageSize: number) {
    return rxRequest<PaginationResponse<OrgsItem>>({
      url: CONFIG.BASE_URL + "/v1/user/follow/getOrgs",
      withJwt: true,
      data: { pageNum, pageSize },
      method: "POST"
    })
  },

  //查看单个关注的主播信息
  getAnchorDetailsSvc(userId: string) {
    return rxRequest<GetAnchorDetailsRsp>({
      url: CONFIG.BASE_URL + `/v1/user/follow/anchorDetails/${userId}`,
      // 需要授权访问
      withJwt: true
    })
  },

  //查看单个关注的机构信息
  getOrgDetailsSvc(orgId: string) {
    return rxRequest<GetOrgDetailsRsp>({
      url: CONFIG.BASE_URL + `/v1/user/follow/orgDetails/${orgId}`,
      // 需要授权访问
      withJwt: true
    })
  },

  //关注的主播或机构的直播动态
  getLatestShowSvc(orgId: string, userId: string) {
    return rxRequest<AnchorlatestRsp[]>({
      url: CONFIG.BASE_URL + '/v1/user/follow/getLatestShow',
      withJwt: true,
      data: { orgId, userId },
      method: "POST"
    })
  },

  //获取我的粉丝列表数据
  getFansSvc(pageNum: number, pageSize: number) {
    return rxRequest<PaginationResponse<FansItem>>({
      url: CONFIG.BASE_URL + "/v1/user/follow/getFans",
      withJwt: true,
      data: { pageNum, pageSize },
      method: "POST"
    })
  },


  // 获取套餐的所有数据
  AllPlanInfoSvc(code: string) {
    return rxRequest<Plans[]>({
      url: CONFIG.BASE_URL + `/v1/user/subs/AllPlanInfo/${code}`,
      // 需要授权访问
      withJwt: true
    })
  },

  //获取订阅权益
  getSubsSvc() {
    return rxRequest<SubscriptionRsp>({
      url: CONFIG.BASE_URL + "/v1/user/subs/subscription",
      // 需要授权访问
      withJwt: true
    })
  },

  //检查订阅是否包含某些权限
  checkSubsSvc(optionValues: string[]) {
    return rxRequest<boolean>({
      url: CONFIG.BASE_URL + "/v1/user/subs/hasSubsRights",
      // 需要授权访问
      withJwt: true
    })
  },

  //开播提醒
  submitsubMsgIdsSvc(appId: string, roomId: string, tmplIds: Array<string>) {
    return rxRequest({
      url: CONFIG.BASE_URL + "/v1/user/app/submitSubMsgIds",
      withJwt: true,
      data: { appId, roomId, tmplIds },
      method: "POST"
    })
  },
}